<!DOCTYPE html>
<html lang="zh" dir="ltr" class="client-nojs">
<head>
<title>函数模板</title>
<meta charset="UTF-8">
<meta name="generator" content="MediaWiki 1.21.2">
<link rel="shortcut icon" href="../../../common/favicon.ico">
<link rel="stylesheet" href="../../../common/ext.css">
<meta name="ResourceLoaderDynamicStyles" content="">
<link rel="stylesheet" href="../../../common/site_modules.css">
<style>a:lang(ar),a:lang(ckb),a:lang(fa),a:lang(kk-arab),a:lang(mzn),a:lang(ps),a:lang(ur){text-decoration:none}#toc{display:none}.editsection{display:none}
/* cache key: mwiki1-mwiki_zh_:resourceloader:filter:minify-css:7:15cea3ec788a65b5187d4018eed543bf */</style>

<script src="../../../common/startup_scripts.js"></script>
<script>if(window.mw){
mw.config.set({"wgCanonicalNamespace":"","wgCanonicalSpecialPageName":false,"wgNamespaceNumber":0,"wgPageName":"cpp/language/function_template","wgTitle":"cpp/language/function template","wgCurRevisionId":61744,"wgArticleId":2718,"wgIsArticle":true,"wgAction":"view","wgUserName":null,"wgUserGroups":["*"],"wgCategories":["Todo with reason","Pages with unreviewed CWG DR marker"],"wgBreakFrames":false,"wgPageContentLanguage":"zh","wgSeparatorTransformTable":["",""],"wgDigitTransformTable":["",""],"wgDefaultDateFormat":"zh","wgMonthNames":["","1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],"wgMonthNamesShort":["","1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],"wgRelevantPageName":"cpp/language/function_template","wgUserVariant":"zh","wgRestrictionEdit":[],"wgRestrictionMove":[]});
}</script><script>if(window.mw){
mw.loader.implement("user.options",function(){mw.user.options.set({"ccmeonemails":0,"cols":80,"date":"default","diffonly":0,"disablemail":0,"disablesuggest":0,"editfont":"default","editondblclick":0,"editsection":0,"editsectiononrightclick":0,"enotifminoredits":0,"enotifrevealaddr":0,"enotifusertalkpages":1,"enotifwatchlistpages":0,"extendwatchlist":0,"externaldiff":0,"externaleditor":0,"fancysig":0,"forceeditsummary":0,"gender":"unknown","hideminor":0,"hidepatrolled":0,"imagesize":2,"justify":0,"math":1,"minordefault":0,"newpageshidepatrolled":0,"nocache":0,"noconvertlink":0,"norollbackdiff":0,"numberheadings":0,"previewonfirst":0,"previewontop":1,"quickbar":5,"rcdays":7,"rclimit":50,"rememberpassword":0,"rows":25,"searchlimit":20,"showhiddencats":0,"showjumplinks":1,"shownumberswatching":1,"showtoc":0,"showtoolbar":1,"skin":"cppreference2","stubthreshold":0,"thumbsize":2,"underline":2,"uselivepreview":0,"usenewrc":0,"watchcreations":0,"watchdefault":0,"watchdeletion":0,
"watchlistdays":3,"watchlisthideanons":0,"watchlisthidebots":0,"watchlisthideliu":0,"watchlisthideminor":0,"watchlisthideown":0,"watchlisthidepatrolled":0,"watchmoves":0,"wllimit":250,"variant":"zh","language":"zh","searchNs0":true,"searchNs1":false,"searchNs2":false,"searchNs3":false,"searchNs4":false,"searchNs5":false,"searchNs6":false,"searchNs7":false,"searchNs8":false,"searchNs9":false,"searchNs10":false,"searchNs11":false,"searchNs12":false,"searchNs13":false,"searchNs14":false,"searchNs15":false,"gadget-MathJax":1,"gadget-ColiruCompiler":1});;},{},{});mw.loader.implement("user.tokens",function(){mw.user.tokens.set({"editToken":"+\\","patrolToken":false,"watchToken":false});;},{},{});
/* cache key: mwiki1-mwiki_zh_:resourceloader:filter:minify-js:7:258d7cd6aa9aa67dee25e01fb6a9e505 */
}</script>
<script>if(window.mw){
mw.loader.load(["mediawiki.page.startup","mediawiki.legacy.wikibits","mediawiki.legacy.ajax"]);
}</script>
<style type="text/css">/*<![CDATA[*/
.source-cpp {line-height: normal;}
.source-cpp li, .source-cpp pre {
	line-height: normal; border: 0px none white;
}
/**
 * GeSHi Dynamically Generated Stylesheet
 * --------------------------------------
 * Dynamically generated stylesheet for cpp
 * CSS class: source-cpp, CSS id: 
 * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann
 * (http://qbnz.com/highlighter/ and http://geshi.org/)
 * --------------------------------------
 */
.cpp.source-cpp .de1, .cpp.source-cpp .de2 {font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;}
.cpp.source-cpp  {font-family:monospace;}
.cpp.source-cpp .imp {font-weight: bold; color: red;}
.cpp.source-cpp li, .cpp.source-cpp .li1 {font-weight: normal; vertical-align:top;}
.cpp.source-cpp .ln {width:1px;text-align:right;margin:0;padding:0 2px;vertical-align:top;}
.cpp.source-cpp .li2 {font-weight: bold; vertical-align:top;}
.cpp.source-cpp .kw1 {color: #0000dd;}
.cpp.source-cpp .kw2 {color: #0000ff;}
.cpp.source-cpp .kw3 {color: #0000dd;}
.cpp.source-cpp .kw4 {color: #0000ff;}
.cpp.source-cpp .co1 {color: #909090;}
.cpp.source-cpp .co2 {color: #339900;}
.cpp.source-cpp .coMULTI {color: #ff0000; font-style: italic;}
.cpp.source-cpp .es0 {color: #008000; font-weight: bold;}
.cpp.source-cpp .es1 {color: #008000; font-weight: bold;}
.cpp.source-cpp .es2 {color: #008000; font-weight: bold;}
.cpp.source-cpp .es3 {color: #008000; font-weight: bold;}
.cpp.source-cpp .es4 {color: #008000; font-weight: bold;}
.cpp.source-cpp .es5 {color: #008000; font-weight: bold;}
.cpp.source-cpp .br0 {color: #008000;}
.cpp.source-cpp .sy0 {color: #008000;}
.cpp.source-cpp .sy1 {color: #000080;}
.cpp.source-cpp .sy2 {color: #000040;}
.cpp.source-cpp .sy3 {color: #000040;}
.cpp.source-cpp .sy4 {color: #008080;}
.cpp.source-cpp .st0 {color: #008000;}
.cpp.source-cpp .nu0 {color: #000080;}
.cpp.source-cpp .nu6 {color: #000080;}
.cpp.source-cpp .nu8 {color: #000080;}
.cpp.source-cpp .nu12 {color: #000080;}
.cpp.source-cpp .nu16 {color:#000080;}
.cpp.source-cpp .nu17 {color:#000080;}
.cpp.source-cpp .nu18 {color:#000080;}
.cpp.source-cpp .nu19 {color:#000080;}
.cpp.source-cpp .ln-xtra, .cpp.source-cpp li.ln-xtra, .cpp.source-cpp div.ln-xtra {background-color: #ffc;}
.cpp.source-cpp span.xtra { display:block; }

/*]]>*/
</style><style type="text/css">/*<![CDATA[*/
.source-text {line-height: normal;}
.source-text li, .source-text pre {
	line-height: normal; border: 0px none white;
}
/**
 * GeSHi Dynamically Generated Stylesheet
 * --------------------------------------
 * Dynamically generated stylesheet for text
 * CSS class: source-text, CSS id: 
 * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann
 * (http://qbnz.com/highlighter/ and http://geshi.org/)
 * --------------------------------------
 */
.text.source-text .de1, .text.source-text .de2 {font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;}
.text.source-text  {font-family:monospace;}
.text.source-text .imp {font-weight: bold; color: red;}
.text.source-text li, .text.source-text .li1 {font-weight: normal; vertical-align:top;}
.text.source-text .ln {width:1px;text-align:right;margin:0;padding:0 2px;vertical-align:top;}
.text.source-text .li2 {font-weight: bold; vertical-align:top;}
.text.source-text .ln-xtra, .text.source-text li.ln-xtra, .text.source-text div.ln-xtra {background-color: #ffc;}
.text.source-text span.xtra { display:block; }

/*]]>*/
</style><!--[if lt IE 7]><style type="text/css">body{behavior:url("/mwiki/skins/cppreference2/csshover.min.htc")}</style><![endif]--></head>
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-cpp_language_function_template skin-cppreference2 action-view cpp-navbar">
        <!-- header -->
        <!-- /header -->
        <!-- content -->
<div id="cpp-content-base">
            <div id="content">
                <a id="top"></a>
                <div id="mw-js-message" style="display:none;"></div>
                                <!-- firstHeading -->
<h1 id="firstHeading" class="firstHeading">函数模板</h1>
                <!-- /firstHeading -->
                <!-- bodyContent -->
                <div id="bodyContent">
                                        <!-- tagline -->
                    <div id="siteSub">来自cppreference.com</div>
                    <!-- /tagline -->
                                        <!-- subtitle -->
                    <div id="contentSub"><span class="subpages">&lt; <a href="../../cpp.html" title="cpp">cpp</a>‎ | <a href="../language.html" title="cpp/language">language</a></span></div>
                    <!-- /subtitle -->
                                                            <!-- bodycontent -->
                    <div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr"><div class="t-navbar" style=""><div class="t-navbar-sep"> </div><div class="t-navbar-head"><a href="../../cpp.html" title="cpp"> C++</a><div class="t-navbar-menu"><div><div><table class="t-nv-begin" cellpadding="0" style="line-height:1.1em;">
<tr class="t-nv"><td colspan="5"> <a href="../language.html" title="cpp/language">语言</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../header.html" title="cpp/header">标准库头文件</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../freestanding.html" title="cpp/freestanding"> 自立与有宿主实现</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../named_req.html" title="cpp/named req">具名要求</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../utility.html#.E8.AF.AD.E8.A8.80.E6.94.AF.E6.8C.81" title="cpp/utility">语言支持库</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../concepts.html" title="cpp/concepts">概念库</a> <span class="t-mark-rev t-since-cxx20">(C++20)</span> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../error.html" title="cpp/error">诊断库</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../utility.html" title="cpp/utility">工具库</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../string.html" title="cpp/string">字符串库</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="https://zh.cppreference.com/w/cpp/container" title="cpp/container">容器库</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../iterator.html" title="cpp/iterator">迭代器库</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../ranges.html" title="cpp/ranges"> 范围库</a> <span class="t-mark-rev t-since-cxx20">(C++20)</span> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../algorithm.html" title="cpp/algorithm">算法库</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../numeric.html" title="cpp/numeric">数值库</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../io.html" title="cpp/io">输入/输出库</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../locale.html" title="cpp/locale">本地化库</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../regex.html" title="cpp/regex">正则表达式库</a> <span class="t-mark-rev t-since-cxx11">(C++11)</span> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../atomic.html" title="cpp/atomic">原子操作库</a> <span class="t-mark-rev t-since-cxx11">(C++11)</span> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../thread.html" title="cpp/thread">线程支持库</a> <span class="t-mark-rev t-since-cxx11">(C++11)</span> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../filesystem.html" title="cpp/filesystem">文件系统库</a> <span class="t-mark-rev t-since-cxx17">(C++17)</span> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="../experimental.html" title="cpp/experimental">技术规范</a> </td></tr>
</table></div><div></div></div></div></div><div class="t-navbar-sep"> </div><div class="t-navbar-head"><a href="../language.html" title="cpp/language">C++ 语言</a></div><div class="t-navbar-sep"> </div><div class="t-navbar-head"><a href="templates.html" title="cpp/language/templates">模板</a><div class="t-navbar-menu"><div><div style="display:inline-block">
<div><table class="t-nv-begin" cellpadding="0" style="">
<tr class="t-nv"><td colspan="5"> <a href="template_parameters.html" title="cpp/language/template parameters">形参与实参</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="class_template.html" title="cpp/language/class template">类模板</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <strong class="selflink">函数模板</strong> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="member_template.html" title="cpp/language/member template">类成员模板</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="variable_template.html" title="cpp/language/variable template">变量模板</a><span class="t-mark-rev t-since-cxx14">(C++14)</span></td></tr>
<tr class="t-nv"><td colspan="5"> <a href="template_argument_deduction.html" title="cpp/language/template argument deduction">模板实参推导</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="class_template_argument_deduction.html" title="cpp/language/class template argument deduction">类模板实参推导</a><span class="t-mark-rev t-since-cxx17">(C++17)</span> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="template_specialization.html" title="cpp/language/template specialization">显式（全）特化</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="partial_specialization.html" title="cpp/language/partial specialization">部分特化</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="dependent_name.html" title="cpp/language/dependent name">待决名</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="parameter_pack.html" title="cpp/language/parameter pack">形参包</a><span class="t-mark-rev t-since-cxx11">(C++11)</span></td></tr>
<tr class="t-nv"><td colspan="5"><div class="t-nv-ln-table"><div><a href="sizeof....html" title="cpp/language/sizeof..."><span class="t-lines"><span>sizeof...</span></span></a></div><div><span class="t-lines"><span><span class="t-mark-rev t-since-cxx11">(C++11)</span></span></span></div></div></td></tr>
<tr class="t-nv"><td colspan="5"> <a href="fold.html" title="cpp/language/fold">折叠表达式</a><span class="t-mark-rev t-since-cxx17">(C++17)</span></td></tr>
<tr class="t-nv"><td colspan="5"> <a href="sfinae.html" title="cpp/language/sfinae"> SFINAE</a> </td></tr>
<tr class="t-nv"><td colspan="5"> <a href="constraints.html" title="cpp/language/constraints">制约与概念</a><span class="t-mark-rev t-since-cxx20">(C++20)</span> </td></tr>
</table></div>
</div><div></div></div></div></div><div class="t-navbar-sep"> </div></div>
<p>函数模板定义一族函数。
</p>
<h3><span class="mw-headline" id=".E8.AF.AD.E6.B3.95">语法</span></h3>
<table class="t-sdsc-begin">

<tr>
<td colspan="10" class="t-sdsc-sep">
</td></tr>
<tr class="t-sdsc">
<td> <code><b>template</b></code> <code><b>&lt;</b></code> <span class="t-spar">形参列表</span> <code><b>&gt;</b></code> <span class="t-spar">函数声明</span>
</td>
<td> (1)
</td>
<td class="t-sdsc-nopad">
</td></tr>



<tr>
<td colspan="10" class="t-sdsc-sep">
</td></tr>
<tr class="t-sdsc">
<td> <code><b>template</b></code> <code><b>&lt;</b></code> <span class="t-spar">形参列表</span> <code><b>&gt;</b></code> <code><b>requires</b></code> <span class="t-spar">制约</span> <span class="t-spar">函数声明</span>
</td>
<td> (2)
</td>
<td> <span class="t-mark-rev t-since-cxx20">(C++20 起)</span>
</td></tr>



<tr>
<td colspan="10" class="t-sdsc-sep">
</td></tr>
<tr class="t-sdsc">
<td> <span class="t-spar">带占位符函数声明</span>
</td>
<td> (3)
</td>
<td> <span class="t-mark-rev t-since-cxx20">(C++20 起)</span>
</td></tr>



<tr>
<td colspan="10" class="t-sdsc-sep">
</td></tr>
<tr class="t-sdsc">
<td> <code><b>export</b></code> <code><b>template</b></code> <code><b>&lt;</b></code> <span class="t-spar">形参列表</span> <code><b>&gt;</b></code> <span class="t-spar">函数声明</span>
</td>
<td> (4)
</td>
<td> <span class="t-mark-rev t-until-cxx11">(C++11 前)</span>
</td></tr>



<tr>
<td colspan="10" class="t-sdsc-sep">
</td></tr></table>
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
<table class="t-par-begin">


<tr class="t-par">
<td>  <span class="t-spar">形参列表</span>
</td>
<td> -
</td>
<td>  非空的<a href="template_parameters.html" title="cpp/language/template parameters">模板形参</a>的逗号分隔列表，每项是<a href="template_parameters.html#.E9.9D.9E.E7.B1.BB.E5.9E.8B.E6.A8.A1.E6.9D.BF.E5.BD.A2.E5.8F.82" title="cpp/language/template parameters">非类型形参</a>、<a href="template_parameters.html#.E7.B1.BB.E5.9E.8B.E6.A8.A1.E6.9D.BF.E5.BD.A2.E5.8F.82" title="cpp/language/template parameters">类型形参</a>、<a href="template_parameters.html#.E6.A8.A1.E6.9D.BF.E6.A8.A1.E6.9D.BF.E5.BD.A2.E5.8F.82" title="cpp/language/template parameters">模板形参</a>或这些的<a href="parameter_pack.html" title="cpp/language/parameter pack">形参包</a>之一。<span class="t-rev-inl t-since-cxx20"><span>与任何模板一样，形参可以<a href="template_parameters.html#.E6.9C.89.E5.88.B6.E7.BA.A6.E6.A8.A1.E6.9D.BF.E5.BD.A2.E5.8F.82" title="cpp/language/template parameters">有制约</a>。</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>
</td></tr>
<tr class="t-par">
<td>  <span class="t-spar">函数声明</span>
</td>
<td> -
</td>
<td> <a href="function.html" title="cpp/language/function">函数声明</a>。所声明的函数名成为模板名。
</td></tr>
<tr class="t-par">
<td>  <span class="t-spar">制约</span><span class="t-mark-rev t-since-cxx20">(C++20)</span>
</td>
<td> -
</td>
<td> <a href="constraints.html" title="cpp/language/constraints">制约表达式</a>，它限制此函数模板接受的模板形参。
</td></tr>
<tr class="t-par">
<td>  <span class="t-spar">带占位符函数声明</span><span class="t-mark-rev t-since-cxx20">(C++20)</span>
</td>
<td> -
</td>
<td> <a href="function.html" title="cpp/language/function">函数声明</a>，其中至少一个形参的类型使用了占位符 <a href="auto.html" title="cpp/language/auto"><code>auto</code></a> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp">Concept <span class="kw4">auto</span></span></span>：模板形参列表将对每个占位符拥有一个虚设形参。（见下文“简写函数模板”）
</td></tr></table>
 <table class="t-rev-begin">
<tr class="t-rev t-until-cxx11"><td>
<p><code>export</code> 是可选的修饰符，声明模板<i>被导出</i>（用于类模板时，它声明所有成员被导出）。对被导出模板进行实例化的文件不需要包含其定义：声明就足够了。<code>export</code> 的实现稀少而且在细节上互不一致。
</p>
</td>
<td><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></td></tr>
</table>
 <table class="t-rev-begin">
<tr class="t-rev t-since-cxx20"><td>
<h3> <span class="mw-headline" id=".E7.AE.80.E5.86.99.E5.87.BD.E6.95.B0.E6.A8.A1.E6.9D.BF">简写函数模板</span></h3>
<p>当函数声明或函数模板声明的形参列表中出现占位符类型（<code>auto</code> 或 <a href="../concepts.html" title="cpp/concepts">Concept auto</a>）时，该声明声明一个函数模板，并且为每个占位符向模板形参列表追加一个虚设的模板形参
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw4">void</span> f1<span class="br0">(</span><span class="kw4">auto</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 与 template&lt;class T&gt; void f(T) 相同</span>
<span class="kw4">void</span> f2<span class="br0">(</span>C1 <span class="kw4">auto</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 若 C1 是概念，则与 template&lt;C1 T&gt; void f2(T) 相同</span>
<span class="kw4">void</span> f3<span class="br0">(</span>C2 <span class="kw4">auto</span>...<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 若 C2 是概念，则与 template&lt;C2... Ts&gt; void f3(Ts...) 相同</span>
<span class="kw4">void</span> f4<span class="br0">(</span><span class="kw4">const</span> C3 <span class="kw4">auto</span><span class="sy2">*</span>, C4 <span class="kw4">auto</span><span class="sy3">&amp;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 与 template&lt;C3 T, C4 U&gt; void f4(const T*, U&amp;); 相同</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw1">class</span> T, C U<span class="sy1">&gt;</span>
<span class="kw4">void</span> g<span class="br0">(</span>T x, U y, C <span class="kw4">auto</span> z<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 与 template&lt;class T, C U, C W&gt; void g(T x, U y, W z); 相同</span></pre></div></div>
<p>简写函数模板可以和所有函数模板一样进行特化。
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;&gt;</span>
<span class="kw4">void</span> f4<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="kw4">const</span> <span class="kw4">int</span><span class="sy2">*</span>, <span class="kw4">const</span> <span class="kw4">double</span><span class="sy3">&amp;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// f4&lt;int, const double&gt; 的特化</span></pre></div></div>
<p><br>
</p>
</td>
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td></tr>
</table>
<h3><span class="mw-headline" id=".E5.87.BD.E6.95.B0.E6.A8.A1.E6.9D.BF.E5.AE.9E.E4.BE.8B.E5.8C.96">函数模板实例化</span></h3>
<p>函数模板自身并不是类型、函数或任何实体。从仅包含模板定义的源文件不生成任何代码。为使得代码出现必须实例化模板：必须确定各模板实参，以令编译器能生成一个实际的函数（或从类模板生成类）。
</p>
<h4><span class="mw-headline" id=".E6.98.BE.E5.BC.8F.E5.AE.9E.E4.BE.8B.E5.8C.96">显式实例化</span></h4>
<table class="t-sdsc-begin">

<tr>
<td colspan="10" class="t-sdsc-sep">
</td></tr>
<tr class="t-sdsc">
<td> <code><b>template</b></code> <span class="t-spar">返回类型</span> <span class="t-spar">名字</span> <code><b>&lt;</b></code>  <span class="t-spar">实参列表</span> <code><b>&gt;</b></code> <code><b>(</b></code> <span class="t-spar">形参列表</span> <code><b>)</b></code> <code><b>;</b></code>
</td>
<td> (1)
</td>
<td class="t-sdsc-nopad">
</td></tr>



<tr>
<td colspan="10" class="t-sdsc-sep">
</td></tr>
<tr class="t-sdsc">
<td> <code><b>template</b></code> <span class="t-spar">返回类型</span> <span class="t-spar">名字</span> <code><b>(</b></code> <span class="t-spar">形参列表</span> <code><b>)</b></code> <code><b>;</b></code>
</td>
<td> (2)
</td>
<td class="t-sdsc-nopad">
</td></tr>



<tr>
<td colspan="10" class="t-sdsc-sep">
</td></tr>
<tr class="t-sdsc">
<td> <code><b>extern</b></code> <code><b>template</b></code> <span class="t-spar">返回类型</span> <span class="t-spar">名字</span> <code><b>&lt;</b></code> <span class="t-spar">实参列表</span> <code><b>&gt;</b></code> <code><b>(</b></code> <span class="t-spar">形参列表</span> <code><b>)</b></code> <code><b>;</b></code>
</td>
<td> (3)
</td>
<td> <span class="t-mark-rev t-since-cxx11">(C++11 起)</span>
</td></tr>



<tr>
<td colspan="10" class="t-sdsc-sep">
</td></tr>
<tr class="t-sdsc">
<td> <code><b>extern</b></code> <code><b>template</b></code> <span class="t-spar">返回类型</span> <span class="t-spar">名字</span> <code><b>(</b></code> <span class="t-spar">形参列表</span> <code><b>)</b></code> <code><b>;</b></code>
</td>
<td> (4)
</td>
<td> <span class="t-mark-rev t-since-cxx11">(C++11 起)</span>
</td></tr>



<tr>
<td colspan="10" class="t-sdsc-sep">
</td></tr></table>
<div class="t-li1"><span class="t-li">1)</span> 显式实例化定义（当每个无默认值模板形参都被显式指定时，无<a href="template_argument_deduction.html" title="cpp/language/template argument deduction">模板实参推导</a>）</div>
<div class="t-li1"><span class="t-li">2)</span> 显式实例化定义，对所有形参进行模板实参推导</div>
<div class="t-li1"><span class="t-li">3)</span> 显示实例化声明（当每个无默认值模板形参都被显式指定时，无模板实参推导）</div>
<div class="t-li1"><span class="t-li">4)</span> 显示实例化声明，对所有形参进行模板实参推导</div>
<p>显式实例化定义强制实例化其所指代的函数或成员函数。它可以出现在程序中模板定义后的任何位置，而对于给定的实参列表，只允许它在整个程序中出现一次。
</p>
 <table class="t-rev-begin">
<tr class="t-rev t-since-cxx11"><td>
<p>显式实例化声明（extern 模板）阻止隐式实例化：本来会导致隐式实例化的代码，必须使用已在程序的别处所提供的显式实例化。
</p>
</td>
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td></tr>
</table>
<p>函数模板特化或成员函数模板特化的显式实例化中，尾部的各模板实参，若能从函数参数<a href="template_argument_deduction.html" title="cpp/language/template argument deduction">推导</a>，则可以不指定
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">typename</span> T<span class="sy1">&gt;</span>
<span class="kw4">void</span> f<span class="br0">(</span>T s<span class="br0">)</span>
<span class="br0">{</span>
    <a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> s <span class="sy1">&lt;&lt;</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
<span class="br0">}</span>
 
<span class="kw1">template</span> <span class="kw4">void</span> f<span class="sy1">&lt;</span><span class="kw4">double</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="kw4">double</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 实例化 f&lt;double&gt;(double)</span>
<span class="kw1">template</span> <span class="kw4">void</span> f<span class="sy1">&lt;&gt;</span><span class="br0">(</span><span class="kw4">char</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 实例化 f&lt;char&gt;(char)，推导出模板实参</span>
<span class="kw1">template</span> <span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 实例化 f&lt;int&gt;(int)，推导出模板实参</span></pre></div></div>
<p>函数模板或类模板成员函数的显式实例化不能使用 <code>inline</code> 或 <code>constexpr</code>。若显式实例化的声明指名了某个隐式声明的特殊成员函数，则程序非良构。
</p><p><a href="constructor.html" title="cpp/language/constructor" class="mw-redirect">构造函数</a>的显式实例化不能使用模板形参列表（语法 <span class="t-v">(1)</span> ），也始终不需要使用，因为能推导它们（语法 <span class="t-v">(2)</span> ）。
</p><p>显式实例化声明并不抑制 <a href="inline.html" title="cpp/language/inline">inline</a> 函数，<a href="auto.html" title="cpp/language/auto">auto</a> 声明，引用，以及类模板特化的隐式实例化。（从而，当作为显式实例化声明目标的 inline 函数被 ODR 式使用时，函数将为内联而隐式实例化，但此翻译单元中不生成其非内联副本）
</p><p>带有<a href="default_arguments.html" title="cpp/language/default arguments">默认实参</a>的函数模板的显式实例化定义，不是对该实参的使用，且不会试图实例化之：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw4">char</span><span class="sy2">*</span> p <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> T g<span class="br0">(</span>T x <span class="sy1">=</span> <span class="sy3">&amp;</span>p<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> x<span class="sy4">;</span> <span class="br0">}</span>
<span class="kw1">template</span> <span class="kw4">int</span> g<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span>   <span class="co1">// OK 即使 &amp;p 不是 int。</span></pre></div></div>
<h4><span class="mw-headline" id=".E9.9A.90.E5.BC.8F.E5.AE.9E.E4.BE.8B.E5.8C.96">隐式实例化</span></h4>
<p>当代码在要求存在函数定义的语境中指涉某个函数，而这个特定函数尚未被显式实例化时，发生隐式实例化。若模板实参列表能从语境<a href="template_argument_deduction.html" title="cpp/language/template argument deduction">推导</a>，则不必提供它。
</p>
<div class="t-example"><div class="t-example-live-link"><div class="coliru-btn coliru-btn-run-init">运行此代码</div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="co2">#include &lt;iostream&gt;</span>
 
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">typename</span> T<span class="sy1">&gt;</span>
<span class="kw4">void</span> f<span class="br0">(</span>T s<span class="br0">)</span>
<span class="br0">{</span>
    <a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> s <span class="sy1">&lt;&lt;</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
<span class="br0">}</span>
 
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
<span class="br0">{</span>
    f<span class="sy1">&lt;</span><span class="kw4">double</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 实例化并调用 f&lt;double&gt;(double)</span>
    f<span class="sy1">&lt;&gt;</span><span class="br0">(</span><span class="st0">'a'</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 实例化并调用 f&lt;char&gt;(char)</span>
    f<span class="br0">(</span><span class="nu0">7</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 实例化并调用 f&lt;int&gt;(int)</span>
    <span class="kw4">void</span> <span class="br0">(</span><span class="sy2">*</span>ptr<span class="br0">)</span><span class="br0">(</span><a href="../string/basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a><span class="br0">)</span> <span class="sy1">=</span> f<span class="sy4">;</span> <span class="co1">// 实例化 f&lt;string&gt;(string)</span>
<span class="br0">}</span></pre></div></div>
<p><br> 
</p>
</div>
<p>注意：完全省略 <code>&lt;&gt;</code> 允许<a href="overload_resolution.html" title="cpp/language/overload resolution">重载决议</a>同时检验模板与非模板重载。
</p>
<h3><span class="mw-headline" id=".E6.A8.A1.E6.9D.BF.E5.AE.9E.E5.8F.82.E6.8E.A8.E5.AF.BC">模板实参推导</span></h3>
<p>为实例化一个<strong class="selflink">函数模板</strong>，每个模板实参都必为已知的，但并非必须指定每个模板实参。只要可能，编译器都会从函数实参推导缺失的模板实参。这发生于尝试进行函数调用时，以及取函数模板的地址时。
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">typename</span> To, <span class="kw1">typename</span> From<span class="sy1">&gt;</span> To convert<span class="br0">(</span>From f<span class="br0">)</span><span class="sy4">;</span>
 
<span class="kw4">void</span> g<span class="br0">(</span><span class="kw4">double</span> d<span class="br0">)</span> 
<span class="br0">{</span>
    <span class="kw4">int</span> i <span class="sy1">=</span> convert<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span>d<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 convert&lt;int,double&gt;(double)</span>
    <span class="kw4">char</span> c <span class="sy1">=</span> convert<span class="sy1">&lt;</span><span class="kw4">char</span><span class="sy1">&gt;</span><span class="br0">(</span>d<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 convert&lt;char,double&gt;(double)</span>
    <span class="kw4">int</span><span class="br0">(</span><span class="sy2">*</span>ptr<span class="br0">)</span><span class="br0">(</span><span class="kw4">float</span><span class="br0">)</span> <span class="sy1">=</span> convert<span class="sy4">;</span> <span class="co1">// 实例化 convert&lt;int, float&gt;(float)</span>
<span class="br0">}</span></pre></div></div>
<p>此机制使得使用模板运算符可行，因为除了将其重写为函数调用表达式之外，不存在为运算符指定模板实参的语法。
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="co2">#include &lt;iostream&gt;</span>
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> 
<span class="br0">{</span>
    <a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"Hello, world"</span> <span class="sy1">&lt;&lt;</span> <a href="../io/manip/endl.html"><span class="kw1791">std::<span class="me2">endl</span></span></a><span class="sy4">;</span>
    <span class="co1">// operator&lt;&lt; 经由 ADL 查找为 std::operator&lt;&lt;，</span>
    <span class="co1">// 然后推导出 operator&lt;&lt;&lt;char, std::char_traits&lt;char&gt;&gt;</span>
    <span class="co1">// 同时推导 std::endl 为 &amp;std::endl&lt;char, std::char_traits&lt;char&gt;&gt;</span>
<span class="br0">}</span></pre></div></div>
<p>模板实参推导在函数模板的<a href="lookup.html" title="cpp/language/lookup">名字查找</a>（可能涉及<a href="adl.html" title="cpp/language/adl">实参依赖查找</a>）之后，在<a href="overload_resolution.html" title="cpp/language/overload resolution">重载决议</a>之间进行。
</p><p>细节见<a href="template_argument_deduction.html" title="cpp/language/template argument deduction">模板实参推导</a>。
</p>
<h3><span class="mw-headline" id=".E6.98.BE.E5.BC.8F.E6.A8.A1.E6.9D.BF.E5.AE.9E.E5.8F.82">显式模板实参</span></h3>
<p>函数模板的模板实参可从以下途径获得
</p>
<ul><li> 模板实参推导
</li><li> 默认模板实参
</li><li> 显式指定，可以在下列语境中进行：
</li></ul>
<dl><dd><ul><li> 于函数调用表达式中
</li><li> 当取函数地址时
</li><li> 当初始化到函数的引用时 
</li><li> 当构成成员函数指针时
</li><li> 于显式特化中
</li><li> 于显式实例化中
</li><li> 于友元声明中
</li></ul>
</dd></dl>
<p>不存在为<a href="operators.html" title="cpp/language/operators">重载的运算符</a>、<a href="cast_operator.html" title="cpp/language/cast operator">转换函数</a>及构造函数显式指定模板实参的方法，因为它们的调用中并未使用函数名。
</p><p>所指定的各模板实参必须与各模板形参在种类上相匹配（即类型对类型，非类型对非类型，模板对模板）。不能有多于形参数量的实参（除非形参之一是形参包，这种情况下对每个非包形参必须有一个实参）。
</p><p>所指定的非类型实参必须要么与其对应的非类型模板形参的类型相匹配，要么<a href="template_parameters.html#.E6.A8.A1.E6.9D.BF.E9.9D.9E.E7.B1.BB.E5.9E.8B.E5.AE.9E.E5.8F.82" title="cpp/language/template parameters">可转换成它们</a>。
</p><p>不参与模板实参推导的函数实参（例如若对应的模板实参已被显式指定），参与到其对应函数形参类型的隐式转换（如在通常<a href="overload_resolution.html" title="cpp/language/overload resolution">重载决议</a>中一样）。
</p><p>当有额外的实参时，模板实参推导可以对显式指定的模板形参包进行扩充：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> ... <span class="me1">Types</span><span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>Types ... <span class="me1">values</span><span class="br0">)</span><span class="sy4">;</span>
<span class="kw4">void</span> g<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
  f<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy2">*</span>, <span class="kw4">float</span><span class="sy2">*</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="nu0">0</span>, <span class="nu0">0</span>, <span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// Types = {int*, float*, int}</span>
<span class="br0">}</span></pre></div></div>
<h3><span class="mw-headline" id=".E6.A8.A1.E6.9D.BF.E5.AE.9E.E5.8F.82.E6.9B.BF.E6.8D.A2">模板实参替换</span></h3>
<p>当已经指定、推导出或从默认模板实参获得了所有的模板实参之后，函数形参列表中对模板形参的每次使用都会被替换成对应的模板实参。
</p><p>函数模板的替换失败（即以推导或提供的模板实参替换模板形参失败），将函数模板从<a href="overload_resolution.html" title="cpp/language/overload resolution">重载集</a>中移除。这就允许使用许多方式通过模板元编程来操作重载集：细节见 <a href="sfinae.html" title="cpp/language/sfinae">SFINAE</a>。
</p><p>替换之后，所有数组和函数类型的函数形参都被调整为指针，而所有顶层 cv 限定符都从函数形参中丢弃（如在常规<a href="function.html#.E5.87.BD.E6.95.B0.E5.A3.B0.E6.98.8E" title="cpp/language/function">函数声明</a>中一样）。
</p><p>去除顶层 cv 限定符并不会影响形参在函数之内所展现的类型：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T t<span class="br0">)</span><span class="sy4">;</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw1">class</span> X<span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span><span class="kw4">const</span> X x<span class="br0">)</span><span class="sy4">;</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw1">class</span> Z<span class="sy1">&gt;</span> <span class="kw4">void</span> h<span class="br0">(</span>Z z, Z<span class="sy2">*</span> zp<span class="br0">)</span><span class="sy4">;</span>
 
<span class="co1">// 两个不同函数具有相同类型，但在函数中，t 有不同的 cv 限定</span>
f<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span>       <span class="co1">// 函数类型是 void(int)，t 为 int</span>
f<span class="sy1">&lt;</span><span class="kw4">const</span> <span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 函数类型是 void(int)，t 为 const int</span>
 
<span class="co1">// 两个不同函数具有相同类型和相同的 x</span>
<span class="co1">// （指向这两个函数的指针不相等，且函数局部的静态变量可以拥有不同地址）</span>
g<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span>       <span class="co1">// 函数类型是 void(int) ， x 为 const int</span>
g<span class="sy1">&lt;</span><span class="kw4">const</span> <span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 函数类型是 void(int) ， x 为 const int</span>
 
<span class="co1">// 仅丢弃顶层 cv 限定符：</span>
h<span class="sy1">&lt;</span><span class="kw4">const</span> <span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="nu0">1</span>, <a href="../types/NULL.html"><span class="kw103">NULL</span></a><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 函数类型是 void(int, const int*) </span>
                       <span class="co1">// z 为 const int ， zp 为 int*</span></pre></div></div>
<h3><span class="mw-headline" id=".E5.87.BD.E6.95.B0.E6.A8.A1.E6.9D.BF.E9.87.8D.E8.BD.BD">函数模板重载</span></h3>
<p>函数模板与非模板函数可以重载。
</p><p>非模板函数始终不同于具有相同类型的模板特化。不同函数模板的特化，即使具有相同类型也始终彼此不同。两个具有相同返回类型和相同形参列表的函数模板是不同的，而且可用显式模板实参列表进行区分。
</p><p>当使用了类型或非类型模板形参的表达式在函数形参列表或返回类型中出现时，为重载的目的，该表达式保留为函数模板签名的一部分：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw4">int</span> I, <span class="kw4">int</span> J<span class="sy1">&gt;</span> A<span class="sy1">&lt;</span>I<span class="sy2">+</span>J<span class="sy1">&gt;</span> f<span class="br0">(</span>A<span class="sy1">&lt;</span>I<span class="sy1">&gt;</span>, A<span class="sy1">&lt;</span>J<span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw4">int</span> K, <span class="kw4">int</span> L<span class="sy1">&gt;</span> A<span class="sy1">&lt;</span>K<span class="sy2">+</span>L<span class="sy1">&gt;</span> f<span class="br0">(</span>A<span class="sy1">&lt;</span>K<span class="sy1">&gt;</span>, A<span class="sy1">&lt;</span>L<span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 同 #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw4">int</span> I, <span class="kw4">int</span> J<span class="sy1">&gt;</span> A<span class="sy1">&lt;</span>I<span class="sy2">-</span>J<span class="sy1">&gt;</span> f<span class="br0">(</span>A<span class="sy1">&lt;</span>I<span class="sy1">&gt;</span>, A<span class="sy1">&lt;</span>J<span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #2</span></pre></div></div>
<p>对于两个涉及模板形参的表达式，若两个包含这些表达式的函数定义根据 <a href="definition.html#.E5.8D.95.E4.B8.80.E5.AE.9A.E4.B9.89.E8.A7.84.E5.88.99.EF.BC.88ODR.EF.BC.89" title="cpp/language/definition">ODR 规则</a>相同，则称它们<i>等价</i>，就是说，除了模板形参的命名可以不同之外，这两个表达式含有相同的记号序列，其中的各个名字通过名字查找都解析到相同实体。<span class="t-rev-inl t-since-cxx20"><span>两个 <a href="lambda.html" title="cpp/language/lambda">lambda 表达式</a>始终不等价。</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw4">int</span> I, <span class="kw4">int</span> J<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>A<span class="sy1">&lt;</span>I<span class="sy2">+</span>J<span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// 模板重载 #1</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw4">int</span> K, <span class="kw4">int</span> L<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>A<span class="sy1">&lt;</span>K<span class="sy2">+</span>L<span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// 等价于 #1</span></pre></div></div>
 <table class="t-rev-begin">
<tr class="t-rev t-since-cxx14"><td>
<p>在确定两个<a href="dependent_name.html" title="cpp/language/dependent name">待决表达式</a>是否等价时，只考虑其中所涉及的各待决名，而不考虑名字查找的结果。如果相同模板的多个声明在名字查找的结果上有所不同，则使用首个这种声明：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> decltype<span class="br0">(</span>g<span class="br0">(</span>T<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span> h<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// decltype(g(T())) 是待决类型</span>
<span class="kw4">int</span> g<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> decltype<span class="br0">(</span>g<span class="br0">(</span>T<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span> h<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="co1">// h() 的再声明使用较早的查找</span>
    <span class="kw1">return</span> g<span class="br0">(</span>T<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>                     <span class="co1">// ……尽管此处的查找找到了 g(int)</span>
<span class="br0">}</span>
<span class="kw4">int</span> i <span class="sy1">=</span> h<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>   <span class="co1">// 模板实参替换失败；在 h() 的首个声明处 g(int) 不在作用域中</span></pre></div></div>
</td>
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td></tr>
</table>
<p>当足下列条件时，认为两个函数模板<i>等价</i>
</p>
<ul><li> 它们声明于同一作用域
</li><li> 它们具有相同的名字
</li><li> 它们拥有<i>等价</i>的模板形参列表，含义是列表长度相同，且对于每对对应的形参，下列内容全为真：
</li></ul>
<dl><dd><ul><li> 二个形参的种类相同（均为类型、均为非类型或均为模板），
</li><li> 它们都是形参包或都不是，
</li><li> 若是非类型，则其类型等价，
</li><li> 若是模板，则其模板形参等价，
</li></ul>
</dd></dl>
 <table class="t-rev-begin">
<tr class="t-rev t-since-cxx20"><td>
<dl><dd><ul><li> 若一者声明带概念名（ concept-name ），则两者都有，且概念名等价。
</li></ul>
</dd></dl>
</td>
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td></tr>
</table>
<ul><li> 其返回类型和形参列表中，各个涉及模板实参的表达式均<i>等价</i>
</li></ul>
 <table class="t-rev-begin">
<tr class="t-rev t-since-cxx20"><td>
<ul><li> 模板形参列表之后的 requires 子句（若存在）中的各个表达式均等价
</li><li> 函数声明符之后的 requires 子句（若存在）中的各个表达式等价
</li></ul>
</td>
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td></tr>
</table>
<p>对于两个涉及模板形参的表达式，如果它们不<i>等价</i>，但对于任何给定的模板实参集，两个表达式的求值都产生相同的值，则称它们<i>功能等价</i>。
</p><p>如果两个函数模板本可<i>等价</i>，但其返回类型和形参列表中一或多个涉及模板形参的表达式<i>功能等价</i>，则称它们<i>功能等价</i>。
</p>
 <table class="t-rev-begin">
<tr class="t-rev t-since-cxx20"><td>
<p>另外，如果为两个函数模板指定的制约不同，但它们接受且被相同的模板实参列表的集合所满足，则它们<i>功能等价</i>但不<i>等价</i>。
</p>
</td>
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td></tr>
</table>
<p>若程序含有<i>功能等价</i>但不<i>等价</i>的函数模板声明，则程序非良构；不要求诊断。
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="co1">// 等价</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw4">int</span> I<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>A<span class="sy1">&lt;</span>I<span class="sy1">&gt;</span>, A<span class="sy1">&lt;</span>I<span class="sy2">+</span><span class="nu0">10</span><span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw4">int</span> I<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>A<span class="sy1">&lt;</span>I<span class="sy1">&gt;</span>, A<span class="sy1">&lt;</span>I<span class="sy2">+</span><span class="nu0">10</span><span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1 的再声明</span>
 
<span class="co1">// 不等价</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw4">int</span> I<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>A<span class="sy1">&lt;</span>I<span class="sy1">&gt;</span>, A<span class="sy1">&lt;</span>I<span class="sy2">+</span><span class="nu0">10</span><span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw4">int</span> I<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>A<span class="sy1">&lt;</span>I<span class="sy1">&gt;</span>, A<span class="sy1">&lt;</span>I<span class="sy2">+</span><span class="nu0">11</span><span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #2</span>
 
<span class="co1">// 功能等价但不等价</span>
<span class="co1">// 程序非良构，不要求诊断</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw4">int</span> I<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>A<span class="sy1">&lt;</span>I<span class="sy1">&gt;</span>, A<span class="sy1">&lt;</span>I<span class="sy2">+</span><span class="nu0">10</span><span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw4">int</span> I<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>A<span class="sy1">&lt;</span>I<span class="sy1">&gt;</span>, A<span class="sy1">&lt;</span>I<span class="sy2">+</span><span class="nu0">1</span><span class="sy2">+</span><span class="nu0">2</span><span class="sy2">+</span><span class="nu0">3</span><span class="sy2">+</span><span class="nu0">4</span><span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 功能等价</span></pre></div></div>
<p>当同一个函数模板特化与多于一个重载的函数模板相匹配时（这通常由<a href="template_argument_deduction.html" title="cpp/language/template argument deduction">模板实参推导</a>所导致），进行<i>重载函数模板的部分排序</i>以选择最佳匹配。
</p><p>具体而言，在以下情形中发生部分排序：
</p>
<div class="t-li1"><span class="t-li">1)</span> 对函数模板特化的调用的<a href="overload_resolution.html" title="cpp/language/overload resolution">重载决议</a>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> X<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>X a<span class="br0">)</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> X<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>X<span class="sy2">*</span> a<span class="br0">)</span><span class="sy4">;</span>
<span class="kw4">int</span><span class="sy2">*</span> p<span class="sy4">;</span>
f<span class="br0">(</span>p<span class="br0">)</span><span class="sy4">;</span></pre></div></div></div>
<div class="t-li1"><span class="t-li">2)</span> 当取得<a href="overloaded_address.html" title="cpp/language/overloaded address">函数模板特化的地址</a>时
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> X<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>X a<span class="br0">)</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> X<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>X<span class="sy2">*</span> a<span class="br0">)</span><span class="sy4">;</span>
<span class="kw4">void</span> <span class="br0">(</span><span class="sy2">*</span>p<span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span><span class="br0">)</span> <span class="sy1">=</span> <span class="sy3">&amp;</span>f<span class="sy4">;</span></pre></div></div></div>
<div class="t-li1"><span class="t-li">3)</span> 选当择作为函数模板特化的<a href="../memory/new/operator_delete.html" title="cpp/memory/new/operator delete">布置 <code>operator delete</code></a> 以匹配布置 <code>operator new</code> 时
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style=""><tr><td class="mbox-empty-cell"></td><td class="mbox-text" style="">本节未完成<br>原因：小示例 </td></tr></table></div>
<div class="t-li1"><span class="t-li">4)</span> 当<a href="friend.html#.E6.A8.A1.E6.9D.BF.E5.8F.8B.E5.85.83" title="cpp/language/friend">友元函数声明</a>、<a href="function_template.html#.E6.98.BE.E5.BC.8F.E5.AE.9E.E4.BE.8B.E5.8C.96" title="cpp/language/function template">显式实例化</a>或<a href="template_specialization.html" title="cpp/language/template specialization">显式特化</a>指代函数模板特化时
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> X<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>X a<span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// 第一个 template f</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> X<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>X<span class="sy2">*</span> a<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 第二个 template f</span>
<span class="kw1">template</span><span class="sy1">&lt;&gt;</span> <span class="kw4">void</span> f<span class="sy1">&lt;&gt;</span><span class="br0">(</span><span class="kw4">int</span> <span class="sy2">*</span>a<span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="co1">// 显式特化</span>
 <span class="co1">// 模板实参推导出现两个候选：</span>
 <span class="co1">// foo&lt;int*&gt;(int*) 与 f&lt;int&gt;(int*)</span>
 <span class="co1">// 部分排序选择 f&lt;int&gt;(int*)，因为它更特殊</span></pre></div></div></div>
<p>非正式而言，“A 比 B 更特殊”意味着“A 比 B 接受更少的类型”。
</p><p>正式而言，为确定任意两个函数模板中哪个更特殊，部分排序过程首先对两个模板之一进行以下变换：
</p>
<ul><li> 对于每个类型、非类型及模板形参，包括形参包，生成一个唯一的虚构类型、值或模板，以之在模板的函数类型中进行替换
</li><li> 若要比较的两个函数模板中只有一个是成员函数，且该函数模板是某个类 <code>A</code> 的非静态成员，则向其形参列表插入一个新的首个形参，当成员函数模板为 &amp;&amp; 限定时，其类型为 <code>cv A&amp;&amp;</code>，否则为 <code>cv A&amp;</code>（其中 cv 是成员函数模板的 cv 限定）——这有助于对运算符的排序，它们是同时作为成员与非成员函数查找的：
</li></ul>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw1">struct</span> B <span class="br0">{</span>
  <span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> R<span class="sy1">&gt;</span> <span class="kw4">int</span> operator<span class="sy2">*</span><span class="br0">(</span>R<span class="sy3">&amp;</span><span class="br0">)</span><span class="sy4">;</span>                     <span class="co1">// #1</span>
<span class="br0">}</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T, <span class="kw1">class</span> R<span class="sy1">&gt;</span> <span class="kw4">int</span> operator<span class="sy2">*</span><span class="br0">(</span>T<span class="sy3">&amp;</span>, R<span class="sy3">&amp;</span><span class="br0">)</span><span class="sy4">;</span>          <span class="co1">// #2</span>
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
  A a<span class="sy4">;</span>
  B<span class="sy1">&lt;</span>A<span class="sy1">&gt;</span> b<span class="sy4">;</span>
  b <span class="sy2">*</span> a<span class="sy4">;</span> <span class="co1">// 模板实参推导对于 int B&lt;A&gt;::operator*(R&amp;) 给出 R=A </span>
         <span class="co1">//           对于 int operator*(T&amp;, R&amp;)，T=B&lt;A&gt;，R=A</span>
<span class="co1">// 为进行部分排序，成员 template B&lt;A&gt;::operator*</span>
<span class="co1">// 被变换成 template&lt;class R&gt; int operator*(B&lt;A&gt;&amp;, R&amp;);</span>
<span class="co1">//     int operator*(   T&amp;, R&amp;)  T=B&lt;A&gt;, R=A</span>
<span class="co1">// 与  int operator*(B&lt;A&gt;&amp;, R&amp;)  R=A 间的部分排序</span>
<span class="co1">// 选择 int operator*(B&lt;A&gt;&amp;, A&amp;) 为更特殊者</span></pre></div></div>
<p>在按上方描述变换两个模板之一后，以变换后模板为实参模板，以另一模板的原模板类型为形参模板，执行<a href="template_argument_deduction.html" title="cpp/language/template argument deduction">模板实参推导</a>。然后以第二个模板（进行变换后）为实参，以第一个模板的原始形式为形参重复这一过程。
</p><p>用于确定顺序的类型取决于语境：
</p>
<ul><li> 在函数调用的语境中，这些类型是在这个函数调用中具有实参的函数形参的类型（不考虑默认函数实参、形参包和省略号形参——见下文）
</li><li> 在调用用户定义的转换函数的语境中，使用转换函数模板的返回类型
</li><li> 在其他语境中，使用函数模板类型
</li></ul>
<p>形参模板中的每个以上列出的类型都被推导。推导开始前，以下列方式对形参模板的每个形参 <code><b>P</b></code> 和实参模板的对应实参 <code><b>A</b></code> 进行调整：
</p>
<ul><li> 若 <code><b>P</b></code> 与 <code><b>A</b></code> 此前均为引用类型，则确定哪个更为 cv 限定（其他所有情况下，就部分排序而言都忽略 cv 限定）
</li><li> 若 <code><b>P</b></code> 是引用类型，则以其所引用的类型替换它
</li><li> 若 <code><b>A</b></code> 是引用类型，则以其所引用的类型替换它
</li><li> 若 <code><b>P</b></code> 有 cv 限定，则 <code><b>P</b></code> 被替换为自身的无 cv 限定版本
</li><li> 若 <code><b>A</b></code> 有 cv 限定，则 <code><b>A</b></code> 被替换为自身的无 cv 限定版本
</li></ul>
<p>在这些调整后，遵循<a href="template_argument_deduction.html#.E4.BB.8E.E7.B1.BB.E5.9E.8B.E6.8E.A8.E5.AF.BC" title="cpp/language/template argument deduction">从类型进行模板实参推导规则</a>，从 <code><b>A</b></code> 推导 <code><b>P</b></code> 。
</p><p>若 P 是函数形参包，则实参模板的每个剩余形参类型的类型 A，都与该函数参数包的声明符标识的类型 P 进行比较。每次比较都为该函数参数包所展开的模板参数包中的后继位置的进行模板实参的推导。
</p><p>若 A 从函数参数包变换而来，则<span class="t-rev-inl t-until-cxx14"><span>推导失败。</span> <span><span class="t-mark-rev t-until-cxx14">(C++14 前)</span></span></span><span class="t-rev-inl t-since-cxx14"><span>将它与形参模板的每个剩余形参类型进行比较。</span> <span><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></span></span>
</p><p>若变换后的模板 1 的实参 <code><b>A</b></code> 可用来推导模板 2 的对应形参 <code><b>P</b></code>，但反之不可，则对于从这一对 P/A 所推导的类型而言，这个 <code><b>A</b></code> 比 <code><b>P</b></code> 更特殊。
</p><p>若双向推导均成功，且原 <code><b>P</b></code> 与 <code><b>A</b></code> 是引用类型，则做附加的测试：
</p>
<ul><li> 若 <code><b>A</b></code> 是左值引用而 <code><b>P</b></code> 是右值引用，则认为 A 比 P 更特殊
</li><li> 若 <code><b>A</b></code> 比 <code><b>P</b></code> 更有 cv 限定，则认为 A 比 P 更特殊
</li></ul>
<p>所有其他情况下，对于这一对 P/A 所推导的类型而言，没有模板比另一个更特殊。
</p><p>在以两个方向考虑每个 P 与 A 后，若对于所考虑的每个类型，
</p>
<ul><li> 模板 1 对所有类型至少与模板 2 一样特殊
</li><li> 模板 1 对某些类型比模板 2 特殊
</li><li> 模板 2 对任何类型都不比模板 1 更特殊，或并非对任何类型都至少一样特殊
</li></ul>
<p>则模板 1 比模板 2 更特殊。若上述条件在切换模板顺序后为真，则模板 2 比模板 1 更特殊。否则，没有模板比另一个更特殊。
持平的情况下，若一个函数模板有一个尾部的形参包而另一个没有，则认为带有被忽略的形参者比有空形参包者更特殊。
</p><p>若在考虑所有的重载模板对之后，有一个无歧义地比所有其他的都更特殊，则选择这个模板的特化，否则编译失败。
</p><p>在下列示例中，虚构实参被称为 U1, U2
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span><span class="sy4">;</span>        <span class="co1">// 模板 #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="sy2">*</span><span class="br0">)</span><span class="sy4">;</span>       <span class="co1">// 模板 #2</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">const</span> T<span class="sy2">*</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 模板 #3</span>
<span class="kw4">void</span> m<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
  <span class="kw4">const</span> <span class="kw4">int</span><span class="sy2">*</span> p<span class="sy4">;</span>
  f<span class="br0">(</span>p<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载决议选取：  #1：void f(T ) [T = const int *]</span>
        <span class="co1">// 　            #2：void f(T*) [T = const int]</span>
        <span class="co1">// 　            #3：void f(const T *) [T = int]</span>
<span class="co1">// 部分排序</span>
<span class="co1">// #1 从变换后的 #2：void(T) 从 void(U1*)：P=T A=U1*：推导 ok：T=U1*</span>
<span class="co1">// #2 从变换后的 #1：void(T*) 从 void(U1)：P=T* A=U1：推导失败</span>
<span class="co1">// 对于 T 而言 #2 比 #1 更特殊</span>
<span class="co1">// #1 从变换后的 #3：void(T) 从 void(const U1*)：P=T, A=const U1*：ok</span>
<span class="co1">// #3 从变换后的 #1：void(const T*) 从 void(U1)：P=const T*, A=U1：失败</span>
<span class="co1">// 对于 T 而言 #3 比 #1 更特殊</span>
<span class="co1">// #2 从变换后的 #3：void(T*) 从 void(const U1*)：P=T* A=const U1*：ok</span>
<span class="co1">// #3 从变换后的 #2：void(const T*) 从 void(U1*)：P=const T* A=U1*：失败</span>
<span class="co1">// 对于 T 而言 #3 比 #2 更特殊</span>
<span class="co1">// 结果：#3 被选择</span>
<span class="co1">// 换言之，f(const T*) 比 f(T) 或 f(T*) 更特殊</span>
<span class="br0">}</span></pre></div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T, T<span class="sy2">*</span><span class="br0">)</span><span class="sy4">;</span>    <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T, <span class="kw4">int</span><span class="sy2">*</span><span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// #2</span>
<span class="kw4">void</span> m<span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span> p<span class="br0">)</span> <span class="br0">{</span>
    f<span class="br0">(</span><span class="nu0">0</span>, p<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #1 的推导：void f(T, T*) [T = int]</span>
             <span class="co1">// #2 的推导：void f(T, int*) [T = int]</span>
 <span class="co1">// 部分排序：</span>
 <span class="co1">// #1 从 #2：void(T,T*) 从 void(U1,int*)：P1=T, A1=U1：T=U1</span>
 <span class="co1">//                                       P2=T*, A2=int*：T=int：失败</span>
 <span class="co1">// #2 从 #1：void(T,int*) 从 void(U1, U2*)：P1=T A1=U1：T=U1</span>
 <span class="co1">//                                         P2=int* A2=U2*：失败</span>
 <span class="co1">// 对于 T 而言无一更特殊，调用有歧义</span>
<span class="br0">}</span></pre></div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T<span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// 模板 #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T<span class="sy3">&amp;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 模板 #2</span>
<span class="kw4">void</span> m<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
  <span class="kw4">float</span> x<span class="sy4">;</span>
  g<span class="br0">(</span>x<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 从 #1 推导：void g(T ) [T = float]</span>
        <span class="co1">// 从 #2 推导：void g(T&amp;) [T = float]</span>
<span class="co1">// 部分排序</span>
<span class="co1">// #1 从 #2：void(T) 从 void(U1&amp;)：P=T, A=U1（调整后）：ok</span>
<span class="co1">// #2 从 #1：void(T&amp;) 从 void(U1)：P=T（调整后） A=U1 ：ok</span>
<span class="co1">// 对于 T 而言无一更特殊，调用有歧义</span>
<span class="br0">}</span></pre></div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw1">struct</span> A <span class="br0">{</span> A<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
 
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> h<span class="br0">(</span><span class="kw4">const</span> T<span class="sy3">&amp;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> h<span class="br0">(</span>A<span class="sy1">&lt;</span>T<span class="sy1">&gt;</span><span class="sy3">&amp;</span><span class="br0">)</span><span class="sy4">;</span>    <span class="co1">// #2</span>
<span class="kw4">void</span> m<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
  A<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span> z<span class="sy4">;</span>
  h<span class="br0">(</span>z<span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// 从 #1 推导：void h(const T &amp;) [T = A&lt;int&gt;]</span>
         <span class="co1">// 从 #2 推导：void h(A&lt;T&gt; &amp;) [T = int]</span>
 <span class="co1">// 部分排序</span>
 <span class="co1">// #1 从 #2：void(const T&amp;) 从 void(A&lt;U1&gt;&amp;)：P=T A=A&lt;U1&gt;：ok T=A&lt;U1&gt;</span>
 <span class="co1">// #2 从 #1：void(A&lt;T&gt;&amp;) 从 void(const U1&amp;)：P=A&lt;T&gt; A=const U1：失败</span>
 <span class="co1">// 对于 T 而言 #2 比 #1 更特殊</span>
 
  <span class="kw4">const</span> A<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span> z2<span class="sy4">;</span>
  h<span class="br0">(</span>z2<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 从 #1 推导：void h(const T&amp;) [T = A&lt;int&gt;]</span>
         <span class="co1">// 从 #2 推导：void h(A&lt;T&gt;&amp;) [T = int]，但替换失败</span>
 <span class="co1">// 只有一个可选择的重载，不尝试部分排序，调用 #1</span>
<span class="br0">}</span></pre></div></div>
<p>因为在调用语境中只考虑有明确的调用实参的形参，故没有明确的调用实参的形参，包括函数形参包、省略号形参及有默认实参的形参均被忽略：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span>  <span class="kw4">void</span>  f<span class="br0">(</span>T<span class="br0">)</span><span class="sy4">;</span>               <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span>  <span class="kw4">void</span>  f<span class="br0">(</span>T<span class="sy2">*</span>, <span class="kw4">int</span><span class="sy1">=</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span>       <span class="co1">// #2</span>
<span class="kw4">void</span> m<span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span> ip<span class="br0">)</span> <span class="br0">{</span>
  <span class="kw4">int</span><span class="sy2">*</span> ip<span class="sy4">;</span>
  f<span class="br0">(</span>ip<span class="br0">)</span><span class="sy4">;</span>     <span class="co1">// 调用 #2（T* 比 T 更特殊）</span>
<span class="br0">}</span></pre></div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span>  T<span class="sy1">&gt;</span>  <span class="kw4">void</span>  g<span class="br0">(</span>T<span class="br0">)</span><span class="sy4">;</span>               <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span>  T<span class="sy1">&gt;</span>  <span class="kw4">void</span>  g<span class="br0">(</span>T<span class="sy2">*</span>, ...<span class="br0">)</span><span class="sy4">;</span>         <span class="co1">// #2</span>
<span class="kw4">void</span> m<span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span> ip<span class="br0">)</span> <span class="br0">{</span>
   g<span class="br0">(</span>ip<span class="br0">)</span><span class="sy4">;</span>     <span class="co1">// 调用 #2（T* 比 T 更特殊）</span>
<span class="br0">}</span></pre></div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T, <span class="kw1">class</span> U<span class="sy1">&gt;</span> <span class="kw1">struct</span> A <span class="br0">{</span> <span class="br0">}</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T, <span class="kw1">class</span> U<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>U, A<span class="sy1">&lt;</span>U,T<span class="sy1">&gt;</span><span class="sy2">*</span> p <span class="sy1">=</span> <span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span>         <span class="kw1">class</span> U<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>U, A<span class="sy1">&lt;</span>U,U<span class="sy1">&gt;</span><span class="sy2">*</span> p <span class="sy1">=</span> <span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #2</span>
<span class="kw4">void</span> h<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
  f<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="nu0">42</span>, <span class="br0">(</span>A<span class="sy1">&lt;</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">&gt;</span><span class="sy2">*</span><span class="br0">)</span><span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// 调用 #2</span>
  f<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="nu0">42</span><span class="br0">)</span><span class="sy4">;</span>                   <span class="co1">// 错误：歧义</span>
<span class="br0">}</span></pre></div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T           <span class="sy1">&gt;</span>  <span class="kw4">void</span> g<span class="br0">(</span>T, T <span class="sy1">=</span> T<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T, <span class="kw1">class</span>... <span class="me1">U</span><span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T, U ...<span class="br0">)</span><span class="sy4">;</span>    <span class="co1">// #2</span>
<span class="kw4">void</span> h<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
  g<span class="br0">(</span><span class="nu0">42</span><span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// 错误：歧义</span>
<span class="br0">}</span></pre></div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span>  T, <span class="kw1">class</span>... <span class="me1">U</span><span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T, U...<span class="br0">)</span><span class="sy4">;</span>           <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span>  T            <span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span><span class="sy4">;</span>                 <span class="co1">// #2</span>
<span class="kw4">void</span> h<span class="br0">(</span><span class="kw4">int</span> i<span class="br0">)</span> <span class="br0">{</span>
  f<span class="br0">(</span><span class="sy3">&amp;</span>i<span class="br0">)</span><span class="sy4">;</span>        <span class="co1">// 调用 #2 因为形参包与无形参之间的决胜规则</span>
                <span class="co1">// （注意：在 DR692 与 DR1395 之间时有歧义）</span>
<span class="br0">}</span></pre></div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span>  T, <span class="kw1">class</span>... <span class="me1">U</span><span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T<span class="sy2">*</span>, U...<span class="br0">)</span><span class="sy4">;</span>          <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span>  T            <span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T<span class="br0">)</span><span class="sy4">;</span>                 <span class="co1">// #2</span>
<span class="kw4">void</span> h<span class="br0">(</span><span class="kw4">int</span> i<span class="br0">)</span> <span class="br0">{</span>
  g<span class="br0">(</span><span class="sy3">&amp;</span>i<span class="br0">)</span><span class="sy4">;</span>        <span class="co1">// OK：调用 #1（T* 比 T 更特殊）</span>
<span class="br0">}</span></pre></div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw1">class</span> ...<span class="me1">T</span><span class="sy1">&gt;</span> <span class="kw4">int</span> f<span class="br0">(</span>T<span class="sy2">*</span>...<span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// #1</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span>  <span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">const</span> T<span class="sy3">&amp;</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #2</span>
f<span class="br0">(</span><span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span><span class="br0">)</span><span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK：选择 #1</span>
            <span class="co1">// （DR1395 之前有歧义，因为两个方向的推导均失败）</span></pre></div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span>... <span class="me1">Args</span><span class="sy1">&gt;</span>           <span class="kw4">void</span> f<span class="br0">(</span>Args... <span class="me1">args</span><span class="br0">)</span><span class="sy4">;</span>               <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T1, <span class="kw1">class</span>... <span class="me1">Args</span><span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T1 a1, Args... <span class="me1">args</span><span class="br0">)</span><span class="sy4">;</span>        <span class="co1">// #2</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T1, <span class="kw1">class</span> T2<span class="sy1">&gt;</span>      <span class="kw4">void</span> f<span class="br0">(</span>T1 a1, T2 a2<span class="br0">)</span><span class="sy4">;</span>               <span class="co1">// #3</span>
f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>                  <span class="co1">// 调用 #1</span>
f<span class="br0">(</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">)</span><span class="sy4">;</span>           <span class="co1">// 调用 #2</span>
f<span class="br0">(</span><span class="nu0">1</span>, <span class="nu0">2</span><span class="br0">)</span><span class="sy4">;</span>              <span class="co1">// 调用 #3；非变参模板 #3 比变参模板 #1 与 #2 更特殊</span></pre></div></div>
<p>在部分排序过程的模板实参推导期间，若实参未被部分排序所考虑的任何类型使用，则不要求该实参与模板形参相匹配
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span>          T f<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// #1</span>
<span class="kw1">template</span> <span class="sy1">&lt;</span><span class="kw1">class</span> T, <span class="kw1">class</span> U<span class="sy1">&gt;</span> T f<span class="br0">(</span>U<span class="br0">)</span><span class="sy4">;</span>    <span class="co1">// #2</span>
<span class="kw4">void</span> g<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
  f<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span>  <span class="co1">// #1 的特化为显式：T f(int) [T = int]</span>
              <span class="co1">// #2 的特化为推导：T f(U) [T = int, U = int]</span>
<span class="co1">// 部分排序（仅考虑实参类型）</span>
<span class="co1">// #1 从 #2：T(int) 从 U1(U2)：失败</span>
<span class="co1">// #2 从 #1：T(U) 从 U1(int)：ok：U=int, T 未使用</span>
<span class="co1">// 调用 #1</span>
<span class="br0">}</span></pre></div></div>
<p>对包含模板形参包的函数模板进行的部分排序，与为这些模板形参包所推导的实参数量无关。
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span>...<span class="sy1">&gt;</span> <span class="kw1">struct</span> Tuple <span class="br0">{</span> <span class="br0">}</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span>          <span class="kw1">class</span>... <span class="me1">Types</span><span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>Tuple<span class="sy1">&lt;</span>Types ...<span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span>        <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T1, <span class="kw1">class</span>... <span class="me1">Types</span><span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>Tuple<span class="sy1">&lt;</span>T1, Types ...<span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span>    <span class="co1">// #2</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T1, <span class="kw1">class</span>... <span class="me1">Types</span><span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>Tuple<span class="sy1">&lt;</span>T1, Types<span class="sy3">&amp;</span> ...<span class="sy1">&gt;</span><span class="br0">)</span><span class="sy4">;</span>   <span class="co1">// #3</span>
 
g<span class="br0">(</span>Tuple<span class="sy1">&lt;&gt;</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>                     <span class="co1">// 调用 #1</span>
g<span class="br0">(</span>Tuple<span class="sy1">&lt;</span><span class="kw4">int</span>, <span class="kw4">float</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>           <span class="co1">// 调用 #2</span>
g<span class="br0">(</span>Tuple<span class="sy1">&lt;</span><span class="kw4">int</span>, <span class="kw4">float</span><span class="sy3">&amp;</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>          <span class="co1">// 调用 #3</span>
g<span class="br0">(</span>Tuple<span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>                  <span class="co1">// 调用 #3</span></pre></div></div>
<p><br>
</p>
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style=""><tr><td class="mbox-empty-cell"></td><td class="mbox-text" style="">本节未完成<br>原因：14.8.3[temp.over] </td></tr></table>
<p>为编译对函数模板的调用，编译器必须在非模板重载、模板重载和模板重载的特化间作出决定。
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span> <span class="kw1">class</span> T <span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span><span class="sy4">;</span>              <span class="co1">// #1：模板重载</span>
<span class="kw1">template</span><span class="sy1">&lt;</span> <span class="kw1">class</span> T <span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="sy2">*</span><span class="br0">)</span><span class="sy4">;</span>             <span class="co1">// #2：模板重载</span>
<span class="kw4">void</span>                     f<span class="br0">(</span><span class="kw4">double</span><span class="br0">)</span><span class="sy4">;</span>         <span class="co1">// #3：非模板重载</span>
<span class="kw1">template</span><span class="sy1">&lt;&gt;</span>          <span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span>            <span class="co1">// #4：#1 的特化</span>
 
f<span class="br0">(</span><span class="st0">'a'</span><span class="br0">)</span><span class="sy4">;</span>        <span class="co1">// 调用 #1</span>
f<span class="br0">(</span>new <span class="kw4">int</span><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 #2</span>
f<span class="br0">(</span><span class="nu16">1.0</span><span class="br0">)</span><span class="sy4">;</span>        <span class="co1">// 调用 #3</span>
f<span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span>          <span class="co1">// 调用 #4</span></pre></div></div>
<h3><span class="mw-headline" id=".E5.87.BD.E6.95.B0.E9.87.8D.E8.BD.BD_vs_.E5.87.BD.E6.95.B0.E7.89.B9.E5.8C.96">函数重载 vs 函数特化</span></h3>
<p>注意，只有非模板和主模板重载参与重载决议。特化并不是重载而不受考虑。只有在重载决议选择最佳匹配的主函数模板后，才检验其特化以查看何者为最佳匹配。
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="kw1">template</span><span class="sy1">&lt;</span> <span class="kw1">class</span> T <span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span><span class="sy4">;</span>    <span class="co1">// #1：所有类型的重载</span>
<span class="kw1">template</span><span class="sy1">&lt;&gt;</span>          <span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #2：针对指向 int 的指针的 #1 的特化</span>
<span class="kw1">template</span><span class="sy1">&lt;</span> <span class="kw1">class</span> T <span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="sy2">*</span><span class="br0">)</span><span class="sy4">;</span>   <span class="co1">// #3：所有指针类型的重载</span>
 
f<span class="br0">(</span>new <span class="kw4">int</span><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 #3，虽然 #1 的特化是完美匹配</span></pre></div></div>
<p>在对翻译单元的头文件进行排序时，记住此规则很重要。有关函数重载与函数特化之间的更多示例，展开于下：
</p>
<hr>
<table style="border-style: none; border-spacing: 2px; width: 100%;" class="mw-collapsible mw-collapsed">

<tr>
<td>
<p><br>
</p>
</td></tr>
<tr>
<td>
<p>首先考虑一些不使用实参依赖查找的场景。对于这种情况，我们使用调用 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="br0">(</span>f<span class="br0">)</span><span class="br0">(</span>t<span class="br0">)</span></span></span>。如 <a href="adl.html" title="cpp/language/adl">ADL</a> 中的描述，将函数名包在括号中可抑制实参依赖查找。
</p>
<ul><li> 声明于 <span class="t-c"><span class="mw-geshi cpp source-cpp">g<span class="br0">(</span><span class="br0">)</span></span></span> 中的<i>引用点</i>（POR，point-of-reference）之前的多个 <span class="t-c"><span class="mw-geshi cpp source-cpp">f<span class="br0">(</span><span class="br0">)</span></span></span> 重载。
</li></ul>
<div class="t-example"><div class="t-example-live-link"><div class="coliru-btn coliru-btn-run-init">运行此代码</div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="co2">#include &lt;iostream&gt;</span>
<span class="kw1">struct</span> A<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span>    <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#1<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// 重载 #1 在 f() POR 前</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="sy2">*</span><span class="br0">)</span>   <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#2<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// 重载 #2 在 f() POR 前</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T<span class="sy2">*</span> t<span class="br0">)</span> 
<span class="br0">{</span>
    <span class="br0">(</span>f<span class="br0">)</span><span class="br0">(</span>t<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// f() POR</span>
<span class="br0">}</span>
 
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
<span class="br0">{</span>
    A <span class="sy2">*</span>p<span class="sy1">=</span>nullptr<span class="sy4">;</span>
    g<span class="br0">(</span>p<span class="br0">)</span><span class="sy4">;</span>
<span class="br0">}</span>           <span class="co1">// POI of g() and f()</span>
 
<span class="co1">// #1 与 #2 都被添加到候选列表；</span>
<span class="co1">// 选择 #2 因为它是较好的匹配。</span></pre></div></div>
<p>输出：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="text source-text"><pre class="de1">#2</pre></div></div> 
</div>
<p><br>
</p>
<ul><li> 匹配较好的模板重载声明于 POR 之后。
</li></ul>
<div class="t-example"><div class="t-example-live-link"><div class="coliru-btn coliru-btn-run-init">运行此代码</div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="co2">#include &lt;iostream&gt;</span>
<span class="kw1">struct</span> A<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span>    <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#1<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T<span class="sy2">*</span> t<span class="br0">)</span> 
<span class="br0">{</span>
    <span class="br0">(</span>f<span class="br0">)</span><span class="br0">(</span>t<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// f() POR</span>
<span class="br0">}</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="sy2">*</span><span class="br0">)</span>   <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#2<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #2</span>
 
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
<span class="br0">{</span>
    A <span class="sy2">*</span>p<span class="sy1">=</span>nullptr<span class="sy4">;</span>
    g<span class="br0">(</span>p<span class="br0">)</span><span class="sy4">;</span>
<span class="br0">}</span>           <span class="co1">// POI of g() and f()</span>
 
<span class="co1">// 仅添加 #1 到候选列表；#2 定义于 POR 之后；</span>
<span class="co1">// 因此，即使它是较佳匹配，它也不为重载所考虑。</span></pre></div></div>
<p>输出：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="text source-text"><pre class="de1">#1</pre></div></div> 
</div>
<p><br>
</p>
<ul><li> 匹配较好的显式模板特化声明于 POR 之后。
</li></ul>
<div class="t-example"><div class="t-example-live-link"><div class="coliru-btn coliru-btn-run-init">运行此代码</div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="co2">#include &lt;iostream&gt;</span>
<span class="kw1">struct</span> A<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span>    <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#1<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T<span class="sy2">*</span> t<span class="br0">)</span> 
<span class="br0">{</span>
    <span class="br0">(</span>f<span class="br0">)</span><span class="br0">(</span>t<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// f() POR</span>
<span class="br0">}</span>
<span class="kw1">template</span><span class="sy1">&lt;&gt;</span>        <span class="kw4">void</span> f<span class="sy1">&lt;&gt;</span><span class="br0">(</span>A<span class="sy2">*</span><span class="br0">)</span> <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#3<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #3</span>
 
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
<span class="br0">{</span>
    A <span class="sy2">*</span>p<span class="sy1">=</span>nullptr<span class="sy4">;</span>
    g<span class="br0">(</span>p<span class="br0">)</span><span class="sy4">;</span>
<span class="br0">}</span>           <span class="co1">// g() 与 f() 的 POI</span>
 
<span class="co1">// 添加 #1 到候选列表；#3 是定义于 POR 后的较好匹配。候选列表由最终被选择的 #1 组成。</span>
<span class="co1">// 之后，声明于 POI 后的 #1 的显式特化 #3 被选择，因为它是较好的匹配。</span>
<span class="co1">// 此行为由 14.7.3/6 [temp.expl.spec] 掌控且与 ADL 无关。</span></pre></div></div>
<p>输出：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="text source-text"><pre class="de1">#3</pre></div></div> 
</div>
<p><br>
</p>
<ul><li> 匹配较好的模板重载声明于 POR 之后。匹配最佳的显式模板特化声明于这个较好的匹配重载之后。
</li></ul>
<div class="t-example"><div class="t-example-live-link"><div class="coliru-btn coliru-btn-run-init">运行此代码</div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="co2">#include &lt;iostream&gt;</span>
<span class="kw1">struct</span> A<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span>    <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#1<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T<span class="sy2">*</span> t<span class="br0">)</span> 
<span class="br0">{</span>
    <span class="br0">(</span>f<span class="br0">)</span><span class="br0">(</span>t<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// f() POR</span>
<span class="br0">}</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="sy2">*</span><span class="br0">)</span>   <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#2<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #2</span>
<span class="kw1">template</span><span class="sy1">&lt;&gt;</span>        <span class="kw4">void</span> f<span class="sy1">&lt;&gt;</span><span class="br0">(</span>A<span class="sy2">*</span><span class="br0">)</span> <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#3<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #3</span>
 
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
<span class="br0">{</span>
    A <span class="sy2">*</span>p<span class="sy1">=</span>nullptr<span class="sy4">;</span>
    g<span class="br0">(</span>p<span class="br0">)</span><span class="sy4">;</span>
<span class="br0">}</span>           <span class="co1">// g() 与 f() 的 POI</span>
 
<span class="co1">// #1 是候选列表的唯一成员且它被最终选择。</span>
<span class="co1">// 之后，跳过显式特化 #3，因为它实际特化了声明于 POR 后的 #2。</span></pre></div></div>
<p>输出：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="text source-text"><pre class="de1">#1</pre></div></div> 
</div>
<p><br>
现在让我们考虑使用实参依赖查找的情况（即我们用更常见的调用格式 <span class="t-c"><span class="mw-geshi cpp source-cpp">f<span class="br0">(</span>t<span class="br0">)</span></span></span>）。
</p>
<ul><li> 匹配较好的模板重载声明于 POR 之后。
</li></ul>
<div class="t-example"><div class="t-example-live-link"><div class="coliru-btn coliru-btn-run-init">运行此代码</div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="co2">#include &lt;iostream&gt;</span>
<span class="kw1">struct</span> A<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span>    <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#1<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T<span class="sy2">*</span> t<span class="br0">)</span> 
<span class="br0">{</span>
    f<span class="br0">(</span>t<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// f() POR</span>
<span class="br0">}</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="sy2">*</span><span class="br0">)</span>   <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#2<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #2</span>
 
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
<span class="br0">{</span>
    A <span class="sy2">*</span>p<span class="sy1">=</span>nullptr<span class="sy4">;</span>
    g<span class="br0">(</span>p<span class="br0">)</span><span class="sy4">;</span>
<span class="br0">}</span>           <span class="co1">// g() 与 f() 的 POI</span>
 
<span class="co1">// #1 被作为常规查找的结果添加到候选列表；</span>
<span class="co1">// #2 定义于 POR 之后但经由 ADL 查找添加到候选列表。</span>
<span class="co1">// #2 作为较好的匹配被选择。</span></pre></div></div>
<p>输出：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="text source-text"><pre class="de1">#2</pre></div></div> 
</div>
<p><br>
</p>
<ul><li> 匹配较好的模板重载声明于 POR 之后。匹配最佳的显式模板实例化声明于这个匹配较好的重载之前。
</li></ul>
<div class="t-example"><div class="t-example-live-link"><div class="coliru-btn coliru-btn-run-init">运行此代码</div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="co2">#include &lt;iostream&gt;</span>
<span class="kw1">struct</span> A<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span>    <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#1<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T<span class="sy2">*</span> t<span class="br0">)</span> 
<span class="br0">{</span>
    f<span class="br0">(</span>t<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// f() POR</span>
<span class="br0">}</span>
<span class="kw1">template</span><span class="sy1">&lt;&gt;</span>        <span class="kw4">void</span> f<span class="sy1">&lt;&gt;</span><span class="br0">(</span>A<span class="sy2">*</span><span class="br0">)</span> <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#3<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #3</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="sy2">*</span><span class="br0">)</span>   <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#2<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #2</span>
 
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
<span class="br0">{</span>
    A <span class="sy2">*</span>p<span class="sy1">=</span>nullptr<span class="sy4">;</span>
    g<span class="br0">(</span>p<span class="br0">)</span><span class="sy4">;</span>
<span class="br0">}</span>           <span class="co1">// g() 与 f() 的 POI</span>
 
<span class="co1">// #1 被作为常规查找的结果添加到候选列表；</span>
<span class="co1">// #2 定义于 POR 之后但经由 ADL 查找添加到候选列表。</span>
<span class="co1">// 作为较好的匹配，从各主模板中选择 #2。</span>
<span class="co1">// 因为 #3 声明于 #2 之前，故它是 #1 的显式特化。</span>
<span class="co1">// 从而最终选择为 #2。</span></pre></div></div>
<p>输出：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="text source-text"><pre class="de1">#2</pre></div></div> 
</div>
<p><br>
</p>
<ul><li> 匹配较好的模板重载声明于 POR 之后，匹配最佳的显式模板特化最后声明。
</li></ul>
<div class="t-example"><div class="t-example-live-link"><div class="coliru-btn coliru-btn-run-init">运行此代码</div></div>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="co2">#include &lt;iostream&gt;</span>
<span class="kw1">struct</span> A<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="br0">)</span>    <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#1<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #1</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> g<span class="br0">(</span>T<span class="sy2">*</span> t<span class="br0">)</span> 
<span class="br0">{</span>
    f<span class="br0">(</span>t<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// f() POR</span>
<span class="br0">}</span>
<span class="kw1">template</span><span class="sy1">&lt;</span><span class="kw1">class</span> T<span class="sy1">&gt;</span> <span class="kw4">void</span> f<span class="br0">(</span>T<span class="sy2">*</span><span class="br0">)</span>   <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#2<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #2</span>
<span class="kw1">template</span><span class="sy1">&lt;&gt;</span>        <span class="kw4">void</span> f<span class="sy1">&lt;&gt;</span><span class="br0">(</span>A<span class="sy2">*</span><span class="br0">)</span> <span class="br0">{</span><a href="../io/cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> <span class="st0">"#3<span class="es1">\n</span>"</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// #3</span>
 
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
<span class="br0">{</span>
    A <span class="sy2">*</span>p<span class="sy1">=</span>nullptr<span class="sy4">;</span>
    g<span class="br0">(</span>p<span class="br0">)</span><span class="sy4">;</span>
<span class="br0">}</span>           <span class="co1">// g() 与 f() 的 POI</span>
 
<span class="co1">// #1 被作为常规查找的结果添加到候选列表；</span>
<span class="co1">// #2 定义于 POR 之后但经由 ADL 查找添加到候选列表。</span>
<span class="co1">// 作为较好的匹配，从各主模板中选择 #2。</span>
<span class="co1">// 因为 #3 声明于 #2 之后，故它是 #2 的显式特化；</span>
<span class="co1">// 从而被选为调用的函数。</span></pre></div></div>
<p>输出：
</p>
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="text source-text"><pre class="de1">#3</pre></div></div> 
</div>
<p><br>
凡在实参为一些 C++ 基础类型时，都没有 ADL 关联的命名空间。从而，这些场景与上述非 ADL 示例等同。
</p>
</td></tr></table>
<hr>
<p>有关重载决议的详细规则，见<a href="overload_resolution.html" title="cpp/language/overload resolution">重载决议</a>。
</p>
<h3><span class="mw-headline" id=".E5.87.BD.E6.95.B0.E6.A8.A1.E6.9D.BF.E7.89.B9.E5.8C.96">函数模板特化</span></h3>
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style=""><tr><td class="mbox-empty-cell"></td><td class="mbox-text" style="">本节未完成<br>原因：14.8[temp.fct.spec] (note that 14.8.1[temp.arg.explicit] 已在全特化专题：要么让函数特化到这里：失去部分特化、与函数重载的交互，或仅引用那边 </td></tr></table>
<h3><span class="mw-headline" id=".E7.BC.BA.E9.99.B7.E6.8A.A5.E5.91.8A">缺陷报告</span></h3>
<p>下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
</p>
<table class="dsctable" style="font-size:0.8em">
<tr>
<th> DR
</th>
<th> 应用于
</th>
<th> 出版时的行为
</th>
<th> 正确行为
</th></tr>
<tr>
<td> <a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1395">CWG 1395</a>
</td>
<td> C++14
</td>
<td> 从形参包推导 A 时失败，且对于空形参包没有决胜规则
</td>
<td> 允许推导，添加决胜规则
</td></tr></table>
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
<ul><li> <a href="class_template.html" title="cpp/language/class template">类模板</a>
</li><li> <a href="function.html" title="cpp/language/function">函数声明</a>
</li></ul>

<!-- 
NewPP limit report
Preprocessor visited node count: 4849/1000000
Preprocessor generated node count: 13121/1000000
Post‐expand include size: 69965/2097152 bytes
Template argument size: 40393/2097152 bytes
Highest expansion depth: 17/40
Expensive parser function count: 0/100
-->

<!-- Saved in parser cache with key mwiki1-mwiki_zh_:pcache:idhash:2718-0!*!0!!zh!*!zh!* and timestamp 20200223044941 -->
</div>                    <!-- /bodycontent -->
                                        <!-- printfooter -->
                    <div class="printfooter">
                    来自“<a href="https://zh.cppreference.com/mwiki/index.php?title=cpp/language/function_template&amp;oldid=61744">https://zh.cppreference.com/mwiki/index.php?title=cpp/language/function_template&amp;oldid=61744</a>”                    </div>
                    <!-- /printfooter -->
                                                            <!-- catlinks -->
                    <!-- /catlinks -->
                                                            <div class="visualClear"></div>
                    <!-- debughtml -->
                                        <!-- /debughtml -->
                </div>
                <!-- /bodyContent -->
            </div>
        </div>
        <!-- /content -->
        <!-- footer -->
        <div id="cpp-footer-base" class="noprint">
            <div id="footer">
                        <div id="cpp-navigation">
            <h5>导航</h5>
            <ul><li><a href="https://zh.cppreference.com/w/cpp/language/function_template">Online version</a></li><li>Offline version retrieved 2020-03-14 18:00.</li></ul></div>
                        <ul id="footer-info">
                                    <li id="footer-info-lastmod"> 本页面最后修改于2019年7月11日 (星期四) 18:26。</li>
                                    <li id="footer-info-viewcount">此页面已被浏览过11,482次。</li>
                            </ul>
                    </div>
        </div>
        <!-- /footer -->
        <script>if(window.mw){
mw.loader.state({"site":"loading","user":"missing","user.groups":"ready"});
}</script>
<script src="../../../common/skin_scripts.js"></script>
<script>if(window.mw){
mw.loader.load(["mediawiki.action.view.postEdit","mediawiki.user","mediawiki.page.ready","mediawiki.searchSuggest","mediawiki.hidpi","ext.gadget.MathJax","ext.gadget.ColiruCompiler"], null, true);
}</script>
<script src="../../../common/site_scripts.js"></script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2828341-1']);
_gaq.push(['_setDomainName', 'cppreference.com']);
_gaq.push(['_trackPageview']);
</script><!-- Served in 4.032 secs. -->
	</body>
<!-- Cached 20200223044941 -->
</html>